package indi.zjh.dp.orm;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.dom4j.DocumentException;
import org.junit.experimental.theories.Theories;
import org.msgpack.annotation.Message;

import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;

import indi.zjh.dp.db.Configuration;
import indi.zjh.dp.db.Session;
import indi.zjh.dp.error.UnsuportedFieldException;
import indi.zjh.dp.type.GTrace;

//@Message
public class Business implements Serializable, Cloneable{
	// 以下划线开头的属性会入库
	// 对象的唯一标识
	protected long _id = 0;
	// 对象创建的时间
	private Date _created = new Date();
	// 对象最后一次被更新的时间
	private Date _updated = new Date();
	// 对象是否被逻辑删除
	private boolean _deleted = false;
	// 是否为测试数据
	private int _f = 0;
	// 对象指向的类名
	private String _class;
	// 乐观锁版本号
	protected long _v;
	
	//private Business self;
	private String selfstring = null;
	// 类名 => id, 用来保存继承关系的多个类对象对应的id
	private Map<String, Long> ids = new HashMap<String, Long>();
	// 类名=> version, 用来保存继承关系的多个类对象对应的版本号
	private Map<String, Long> vers = new HashMap<String, Long>();
	
	
	public Business()
	{
		
	}
	
	public void delete()
	{
		this._deleted = true;
	}
	
	public boolean isDelete()
	{
		return this._deleted;
	}

	public long getId()
	{
		if(this.ids.containsKey(this.getClass().getName()))
		{
			return this.ids.get(this.getClass().getName()).longValue();
		}
		return this._id;
	}
	
	
	/**
	 * 获取指定父类对象的Id
	 * @param clsname
	 * @return
	 */
	public long getSpecId(Class<?> cls)
	{
		String clsname = cls.getName();
		if(!this.ids.containsKey(clsname))
			return 0;
		return this.ids.get(clsname).longValue();
	}
	
	public long getSpecId(String clsname)
	{
		if(!this.ids.containsKey(clsname))
			return 0;
		return this.ids.get(clsname).longValue();
	}
	
	protected void setId(long id)
	{
		this._id = id;
	}

	/**
	 * 获取乐观锁版本号
	 * @return
	 */
	public long getVersion()
	{
		if(this.vers.containsKey(this.getClass().getName()))
		{
			return this.vers.get(this.getClass().getName()).longValue();
		}
		return this._v;
	}
	
	public long getSpecVersion(Class<?> cls)
	{
		String clsname = cls.getName();
		if(!this.vers.containsKey(clsname))
			return this._v;
		return this.vers.get(clsname).longValue();
	}
	
	public long getSpecVersion(String clsname)
	{
		if(!this.vers.containsKey(clsname))
			return this._v;
		return this.vers.get(clsname).longValue();
	}
	
	/**
	 * 自增乐观锁版本号
	 */
	private void incrVersion(String clsname)
	{
		//++this._v;
		
		Long lv = this.vers.get(clsname);
		if(lv != null)
		{
			this.vers.put(clsname, lv.longValue()+1);
		}
		if(this.getClass().getName().equals(clsname))
			++this._v;
		
	}
	
	public void debug()
	{
		System.out.println(this.toString());
	}
	
	/**
	 * 当对象的值被修改后, 在入库之前获取对象的修改时间
	 */
	protected void updateWriteTimestamp()
	{
		this._updated = new Date();
	}
	
	/**
	 * 保存当前对象的值的状态, 当对象的值从数据库初始化的时候会标记一下
	 * @throws CloneNotSupportedException
	 */
	protected void mark() throws CloneNotSupportedException
	{
		this.selfstring = this.toString();
	}
	
	/**
	 * 判断该业务对象从数据库初始化到此刻有没有被修改过, 修改过才会入库
	 * @return
	 * @throws Exception 
	 * @throws DocumentException 
	 * @throws UnsuportedFieldException 
	 */
	protected boolean isModified() throws UnsuportedFieldException, DocumentException, Exception
	{
		if(this.selfstring == null)
		{
			return true;
		}
		if(this._deleted)
		{
			return true;
		}
			
		
		// 判断聚合对象是否被修改
		RelationClass rc = Configuration.getInstance().getVersion().getRelationClass(this.getClass().getName());
		Iterator<Map.Entry<String, String>> iter = rc.aggregationFieldMap.entrySet().iterator();
		while(iter.hasNext())
		{
			Map.Entry<String, String> entry = iter.next();
			Field f = rc.getClazz().getDeclaredField(entry.getKey());
			f.setAccessible(true);
			GTrace<Long> idset = (GTrace<Long>)f.get(this);
			if(idset.getFinalAddSet().size() > 0 || idset.getFinalRemoveSet().size() > 0)
			{
				return true;
			}
				
		}
		
		// 判断关联关系是否被修改
		Iterator<Field> iterf = rc.associationFieldSet.iterator();
		while(iterf.hasNext())
		{
			Field f = iterf.next();
			f.setAccessible(true);
			Relation rel = (Relation)f.get(this);
			if(rel.getIdSet().getFinalAddSet().size() > 0 || rel.getIdSet().getFinalRemoveSet().size() > 0)
			{
				return true;
			}
		}

		return !this.selfstring.equals(this.toString());
	}
	

	
	/**
	 * 判断该对象是否被别的对象包含过
	 * @return
	 * @throws Exception 
	 * @throws DocumentException 
	 * @throws SQLException 
	 */
	protected boolean isContained(Session sess) throws SQLException, DocumentException, Exception
	{
		if(this._id == 0)
			return false;
		
		try
		{
			RelationClass rc = Configuration.getInstance().getVersion().getRelationClass(this.getClass().getName());
			if(rc.containedClass == null)
				return false;
			Iterator<RelationClass> iter = rc.containedClass.iterator();
			while(iter.hasNext())
			{
				RelationClass rrc = iter.next();
				String selectSql = RelationStrategy.getRelateValueSqlB(rrc, rc, this._id, RelationStrategy.COMPOSITION);
				List<Map<String, Object>> rrows = null;
				
				// 处理关系表不存在的情况
				boolean isSkip = false;
				try
				{
					rrows = sess.query(selectSql);
				}
				catch(MySQLSyntaxErrorException ee)
				{
					if(ee.getMessage().indexOf("Table") != -1 && ee.getMessage().indexOf("doesn't exist") != -1)
						isSkip = true;
					else
						throw ee;
				}
				catch(SQLException ee)
				{
					if(ee.getMessage().indexOf("no such table") != -1)
						isSkip = true;
					else
						throw ee;
				}
				if(isSkip)
					continue;
				if(rrows.size() > 0)
				{
					return true;
				}
			}
		}
		catch(Exception e)
		{
			throw e;
		}

		return false;
	}

	/**
	 * 判断该对象有没有被聚合包含过
	 * @return
	 * @throws Exception 
	 */
	protected boolean isGrouped(Session sess) throws Exception
	{
		if(this._id == 0)
			return false;
		
		try
		{
			RelationClass rc = Configuration.getInstance().getVersion().getRelationClass(this.getClass().getName());
			Iterator<RelationClass> iter = rc.aggregationedClass.iterator();
			while(iter.hasNext())
			{
				RelationClass rrc = iter.next();
				String selectSql = RelationStrategy.getRelateValueSqlB(rrc, rc, this._id, RelationStrategy.AGGREGATION);
				List<Map<String, Object>> rrows = sess.query(selectSql);
				if(rrows.size() > 0)
				{
					return true;
				}
			}
		}
		catch(Exception e)
		{
			throw e;
		}
		return false;
	}
	

	

	
	protected void saveId(String clsname, long id)
	{
		this.ids.put(clsname, id);
		if(this.getClass().getName().equals(clsname))
			this._id = id;
	}
	
	protected void saveVersion(String clsname, long v)
	{
		this.vers.put(clsname, v);
		if(this.getClass().getName().equals(clsname))
			this._v = v;
	}
	

	private Map<String, Long> getIds()
	{
		return this.ids;
	}
	public void printIds()
	{
		System.out.println("打印所有Ids, 当前类:"+this.getClass().getName()+", id个数:"+this.ids.size());
		Iterator<Map.Entry<String, Long>> iter = this.ids.entrySet().iterator();
		String[] strs = new String[this.ids.size()];
		int i = 0;
		while(iter.hasNext())
		{
			Map.Entry<String, Long> entry = iter.next();
			strs[i++] = entry.getKey()+"["+entry.getValue()+"]";
		}
		System.out.println("\t"+String.join(",", strs));
	}
	public void printVersions()
	{
		System.out.println("打印所有Versions, 当前类:"+this.getClass().getName()+", version个数:"+this.vers.size());
		Iterator<Map.Entry<String, Long>> iter = this.vers.entrySet().iterator();
		String[] strs = new String[this.vers.size()];
		int i = 0;
		while(iter.hasNext())
		{
			Map.Entry<String, Long> entry = iter.next();
			strs[i++] = entry.getKey()+"["+entry.getValue()+"]";
		}
		System.out.println("\t"+String.join(",", strs));
	}
	
	/**
	 * 获取属性在数据库中的解释
	 * @param f
	 * @return
	 */
	public static String toDictString(Field f)
	{
		return f.getName();
	}
	
	public static String toDictString(Method m)
	{
		return "";
	}
	public Date getCreated()
	{
		return this._created;
	}
	
	public Date getUpdated()
	{
		return this._updated;
	}
}
